Skip to content

feat(ui): implement predictive back gesture and migrate Key.Back to BackHandler - #498

Merged
ProdigyV21 merged 6 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/predictive-back-gesture
Aug 12, 2026
Merged

feat(ui): implement predictive back gesture and migrate Key.Back to BackHandler#498
ProdigyV21 merged 6 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/predictive-back-gesture

Conversation

@Himanth-reddy

Copy link
Copy Markdown
Collaborator

Summary

This PR implements predictive back gesture support for the Stream Searching page (StreamSelector.kt) and refactors app-wide back navigation handling to ensure compatibility with Android 13+ (OnBackPressedDispatcher).

Key Changes

  1. Predictive Back Support (StreamSelector.kt & AndroidManifest.xml)

    • Enabled android:enableOnBackInvokedCallback="true" in AndroidManifest.xml.
    • Added Compose PredictiveBackHandler in StreamSelector.kt with top-level progress tracking.
    • Separated StreamSelector root layout into an outer scrim Box (animating dark overlay alpha) and an inner content Box (animating scale, translation, and alpha via graphicsLayer).
    • Handled coroutine cancellation properly by rethrowing CancellationException.
  2. App-Wide Key.Back -> BackHandler Migration (25 Files)

    • Replaced legacy Compose Key.Back interceptions with BackHandler across all screens, overlays, and modals to prevent back navigation from breaking when enableOnBackInvokedCallback="true" is active on API 33+.
    • Retained Key.Escape in key listeners for hardware keyboard and desktop users.
    • Ensured single-ownership rule for back handling inside modals and overlays.

@Himanth-reddy
Himanth-reddy force-pushed the feat/predictive-back-gesture branch 3 times, most recently from 5e9f121 to fc777c6 Compare July 28, 2026 11:52
…Selector

- Create ArvioPredictiveBack motion primitive (M3 surface scale 90%, edge-aware shift, touchY tilt, and instant release handling)
- Apply ArvioBackSurface, ArvioBackPeek, and AnimatedVisibility exit transitions to SettingsScreen sub-pages
- Apply ArvioBackModal and smooth fade/slide-down exit transitions to StreamSelector modal overlay
@Himanth-reddy
Himanth-reddy force-pushed the feat/predictive-back-gesture branch from f2f5bc1 to d65e5ff Compare July 29, 2026 12:34
@Himanth-reddy
Himanth-reddy marked this pull request as ready for review July 29, 2026 12:46

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5df9fb5c05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

android:allowBackup="false"
android:banner="@drawable/app_banner"
android:enableOnBackInvokedCallback="false"
android:enableOnBackInvokedCallback="true"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Finish migrating Key.Back before enabling predictive back

With this application-wide flag enabled on API 33+ / targetSdk 36, system Back is delivered through the OnBackInvoked/OnBackPressed path instead of the Compose key-event path, but a repo-wide check still shows screens and modals that only handle Key.Back in onKeyEvent/onPreviewKeyEvent and have no BackHandler in those files, e.g. app/src/main/kotlin/com/arflix/tv/ui/components/TextInputModal.kt:142 and app/src/main/kotlin/com/arflix/tv/ui/screens/plugin/PluginScreen.kt:130. In those contexts Back will no longer dismiss/navigate as intended and can fall through to the activity/root back behavior, so either keep this flag off or migrate the remaining Key.Back handlers to BackHandler before enabling it globally.

Useful? React with 👍 / 👎.

@ProdigyV21 ProdigyV21 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Himanth — ArvioPredictiveBack.kt is genuinely good work: M3-spec easing, real commit/cancel settle animations, and the CancellationException rethrow is handled correctly. The StreamSelector and mobile Settings integrations look right. This is closer to mergeable than #495, but there's one blocker that makes it dangerous to land as-is.

Blocker: the manifest flag is flipped app-wide, but the migration it requires isn't in this PR.

The description says "App-Wide Key.BackBackHandler Migration (25 Files)" — the diff migrates exactly one (StreamSelector). Checked against the branch:

  • The codebase has 55 Key.Back interceptions across 25 files. After this PR, 54 remain: PlayerScreen keeps 7, the TV Settings layout keeps 14, and 17 files — every context menu, AudioTrackSelector, PersonModal, TextInputModal, QuickZapOverlay, SearchOverlay, NextEpisodeOverlay, DetailsScreen, EpgGrid, and more — have Key.Back as their only back mechanism, with no BackHandler at all.
  • With enableOnBackInvokedCallback="true" and targetSdk 36, Android 13+ stops delivering KEYCODE_BACK to the app's views entirely — that's the documented contract of opting in. Every remaining interceptor goes silently dead on Android 13+.
  • Concrete failure: on a Google TV Streamer (Android 14), Back with a context menu open no longer closes the menu — it fires whatever BackHandler sits underneath (or exits the screen) while the menu stays on screen. Same for the audio-track selector during playback, the person modal, text input, quick-zap… Back is the navigation primitive on TV, and this forks its behavior by OS version: fine on Android ≤ 12, broken on 13+.

Note the risk/benefit inversion: predictive back gestures don't exist on TV (d-pad Back commits with no progress events), so the flag's visible benefit is mobile-only — while the breakage lands on the TV form factor.

What would make this mergeable — either path works:

  1. Do the migration the description promises: move all 55 Key.Back sites to BackHandler/PredictiveBackHandler with correct enabled state and modal ownership (topmost layer wins), then flip the flag — and test on an actual Android 13+ device, since ≤ 12 can't reveal any of these regressions.
  2. Ship the motion work now, defer the flag: keep enableOnBackInvokedCallback="false", land ArvioPredictiveBack.kt + the StreamSelector/Settings integrations (they work fine via the compat dispatcher), and flip the flag in a follow-up once the migration is complete.

Option 2 gets your animation work in quickly and safely.

Also please split out the TvLazyColumnLazyColumn migration in StreamSelector. It changes d-pad focus/scroll behavior in the source picker, it's unrelated to predictive back, and it deserves its own PR where it can be reviewed and tested as what it is.

@Himanth-reddy
Himanth-reddy requested a review from ProdigyV21 July 30, 2026 17:05
@Himanth-reddy

Copy link
Copy Markdown
Collaborator Author

Thanks @ProdigyV21! Addressed all review feedback in the latest commit () on :

1. Completed App-Wide Migration (Option 1)

  • Kept in .
  • Replaced legacy handling across all 25 files with Compose / with explicit ownership and state management:
    • Modals & Overlays: PersonModal, TextInputModal, QuickActionMenu, NextEpisodeOverlay, MediaContextMenu, ContextMenu, AudioTrackSelector, AppUpdateModal
    • Live TV & EPG: SearchOverlay, QuickZapOverlay, LiveTvEnhancements, EpgGrid, CategorySidebar, LiveTvScreen
    • Player & Screens: PlayerScreen, HomeScreen, SearchScreen, WatchlistScreen, DetailsScreen, CollectionDetailsScreen, PluginScreen, TelegramSettingsScreen, SettingsScreen (TV layout & dialogs).
  • Ensured topmost overlay/modal handles dismissal first, preventing background screens from capturing back events.

2. Isolated in

  • Reverted back to TvLazyColumn (and rememberTvLazyListState) in StreamSelector.kt to keep scrolling/focus behavior changes isolated.
  • Kept all ArvioPredictiveBack motion primitives and arvioBackModal animations intact.

3. Verification

  • Verified compilation with ./gradlew :app:compileSideloadDebugKotlin (BUILD SUCCESSFUL).

@github-actions github-actions Bot added the area: android Changes to the Android app or Gradle build label Aug 12, 2026
@ProdigyV21
ProdigyV21 merged commit 76da45c into ProdigyV21:main Aug 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: android Changes to the Android app or Gradle build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants